package com.chaosj.xml;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONObject;
import com.alipay.hessian.generic.model.GenericObject;
import com.alipay.sofa.rpc.api.GenericService;
import com.alipay.sofa.rpc.config.ConsumerConfig;
import lombok.Data;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @className: RemoteRpcCallEntry
 * @description:
 * @author: caoyangjie
 * @date: 2022/5/15
 **/
@Data
public class RemoteRpcServiceEntry {
    private String interfaceName;
    private String methodName;
    private List<RemoteRpcClassEntry> request;
    private RemoteRpcClassEntry response;

    private GenericService getRemoteService(){
        ConsumerConfig<GenericService> bConsumerV3 = new ConsumerConfig<GenericService>()
                .setInterfaceId(interfaceName)
                .setGeneric(true)
                .setDirectUrl("bolt://127.0.0.1:22222")
                .setTimeout(3000)
                .setRetries(2);
        return bConsumerV3.refer();
    }

    public JSONObject invoke(Object[] requestData) {
        String[] argTypes = new String[request.size()];
        Object[] requestArgs = new Object[request.size()];
        for( int i = 0; i < request.size(); i ++ ){
            argTypes[i] = request.get(i).getClazz();
            requestArgs[i] = doGenerate(request.get(i), requestData[i]);
        }
        GenericObject result = (GenericObject) getRemoteService().$genericInvoke(methodName, argTypes, requestArgs);
        return doConvert(result);
    }

    private JSONObject doConvert(GenericObject result) {
        if( response==null ){
            return null;
        }
        if(CollectionUtil.isEmpty(response.getRef()) ){
            return new JSONObject(result.getFields());
        }
        Map<String,Object> fieldValues = result.getFields();
        Map<String,Object> otherMap = new HashMap<>();
        response.getRef().forEach((k,v)->{
            otherMap.put(k,fieldValues.remove(k));
        });
        JSONObject convertResult = new JSONObject(fieldValues);
        otherMap.forEach((k,v)->{
            convertResult.putIfAbsent(k,doConvert((GenericObject) v));
        });
        return convertResult;
    }

    private Object doGenerate(RemoteRpcClassEntry remoteRpcClassEntry, Object requestData) {
        if( requestData==null ){
            return new JSONObject();
        }
        if(remoteRpcClassEntry.isBase() ){
            return requestData;
        }
        GenericObject request = new GenericObject(remoteRpcClassEntry.getClazz());
        JSONObject json = requestData instanceof JSONObject ? (JSONObject) requestData : new JSONObject(requestData);
        json.keySet().stream().filter(key->CollectionUtil.isEmpty(remoteRpcClassEntry.getRef())||!remoteRpcClassEntry.getRef().containsKey(key)).forEach(k->{
            request.putField(k,json.get(k));
        });
        remoteRpcClassEntry.getRef().forEach((k,v)->{
            request.putField(k, doGenerate(v, json.get(k)));
        });
        return request;
    }
}
